import javafx.animation.AnimationTimer;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.stage.Stage;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 游戏界面类，处理所有UI相关逻辑
 */
public class GameUI {
    private static final Logger LOGGER = Logger.getLogger(GameUI.class.getName());

    private final GameState state;
    private final GameLogic logic;
    private final ImageView[][] cells = new ImageView[GameState.ROWS][GameState.COLS];
    private ImageView firstSelected = null;
    private Label timeLabel;
    private Label scoreLabel;
    private Label hintLabel;
    private Label shuffleLabel;
    private Button hintBtn;
    private Button shuffleBtn;
    private boolean hintActive = false;
    private int[] hintPos1, hintPos2;
    private AnimationTimer timer;
    private final List<Image> images = new ArrayList<>();
    private Image bgImage;

    public GameUI(GameState state, GameLogic logic) {
        this.state = state;
        this.logic = logic;
    }

    public void loadImages() {
        // 加载背景图片
        try (InputStream bgStream = getClass().getResourceAsStream("bg.jpg")) {
            bgImage = bgStream != null ? new Image(bgStream) : createBlankImage();
        } catch (Exception e) {
            LOGGER.log(Level.WARNING, "加载背景图片失败", e);
            bgImage = createBlankImage();
        }

        // 加载游戏元素图片
        for (int i = 1; i <= GameState.KIND_COUNT; i++) {
            try (InputStream imgStream = getClass().getResourceAsStream(i + ".png")) {
                images.add(imgStream != null ? new Image(imgStream) : createBlankImage());
            } catch (Exception e) {
                LOGGER.log(Level.WARNING, "加载图片 " + i + ".png 失败", e);
                images.add(createBlankImage());
            }
        }
    }

    private Image createBlankImage() {
        return new Image(new ByteArrayInputStream(new byte[0]));
    }

    public void setupUI(Stage primaryStage) {
        // 初始化游戏界面
        VBox root = createRootLayout();

        // 创建游戏网格
        GridPane gameGrid = createGameGrid();

        // 创建操作按钮栏
        HBox buttonBar = createButtonBar(gameGrid);

        // 组装界面
        root.getChildren().addAll(createTitleLabel(), createStatusBar(), gameGrid, buttonBar);

        // 设置舞台并显示
        setupAndShowStage(primaryStage, root);

        // 启动计时
        startTimer();
    }

    private VBox createRootLayout() {
        VBox root = new VBox(10);
        root.setAlignment(Pos.CENTER);
        root.setBackground(new Background(
                new BackgroundFill(Color.rgb(240, 240, 240), CornerRadii.EMPTY, null)
        ));
        root.setPadding(new Insets(10));
        return root;
    }

    private Label createTitleLabel() {
        Label title = new Label("连连看小游戏");
        title.setFont(Font.font("微软雅黑", 30));
        title.setAlignment(Pos.CENTER);
        title.setTextFill(Color.DARKBLUE);
        return title;
    }

    private HBox createStatusBar() {
        HBox statusBar = new HBox(20);
        statusBar.setAlignment(Pos.CENTER);

        timeLabel = createStatusLabel("剩余时间: " + GameState.TIMER_LIMIT + " 秒");
        scoreLabel = createStatusLabel("得分: 0");
        hintLabel = createStatusLabel("提示: " + state.hintsLeft + " 次");
        shuffleLabel = createStatusLabel("重排: " + state.shufflesLeft + " 次");

        statusBar.getChildren().addAll(timeLabel, scoreLabel, hintLabel, shuffleLabel);
        return statusBar;
    }

    private GridPane createGameGrid() {
        GridPane gameGrid = new GridPane();
        gameGrid.setAlignment(Pos.CENTER);
        gameGrid.setHgap(2);
        gameGrid.setVgap(2);
        initGameGrid(gameGrid);
        return gameGrid;
    }

    private HBox createButtonBar(GridPane gameGrid) {
        HBox buttonBar = new HBox(15);
        buttonBar.setAlignment(Pos.CENTER);

        hintBtn = createButton("提示 (" + state.hintsLeft + ")", e -> showHint(gameGrid));
        shuffleBtn = createButton("重排 (" + state.shufflesLeft + ")", e -> shuffleMap(gameGrid));

        buttonBar.getChildren().addAll(
                createButton("重新开始", e -> resetGame(gameGrid)),
                hintBtn,
                shuffleBtn
        );
        return buttonBar;
    }

    private void setupAndShowStage(Stage primaryStage, VBox root) {
        Scene scene = new Scene(root,
                GameState.COLS * GameState.CELL_SIZE + 120,
                GameState.ROWS * GameState.CELL_SIZE + 250);

        primaryStage.setTitle("JavaFX 连连看");
        primaryStage.setScene(scene);
        primaryStage.setResizable(false);
        primaryStage.show();
    }

    private Label createStatusLabel(String text) {
        Label label = new Label(text);
        label.setFont(Font.font("微软雅黑", 16));
        label.setTextFill(Color.DARKSLATEBLUE);
        return label;
    }

    private Button createButton(String text, javafx.event.EventHandler<javafx.event.ActionEvent> handler) {
        Button button = new Button(text);
        button.setFont(Font.font("微软雅黑", 14));
        button.setStyle("-fx-background-color: #4CAF50; -fx-text-fill: white;");
        button.setOnAction(handler);
        button.setMinWidth(100);
        return button;
    }

    private void initGameGrid(GridPane gameGrid) {
        for (int row = 0; row < GameState.ROWS; row++) {
            for (int col = 0; col < GameState.COLS; col++) {
                ImageView cell = createCell(row, col, gameGrid);
                cells[row][col] = cell;
                gameGrid.add(cell, col, row);
            }
        }
    }

    private ImageView createCell(int row, int col, GridPane gameGrid) {
        ImageView cell = new ImageView();
        cell.setFitWidth(GameState.CELL_SIZE);
        cell.setFitHeight(GameState.CELL_SIZE);
        cell.setImage(getImageByType(state.map[row][col]));

        cell.setOnMouseClicked(e -> onCellClicked(cell, row, col, gameGrid));
        return cell;
    }

    private Image getImageByType(int type) {
        return type == 0 ? bgImage : images.get(type - 1);
    }

    @SuppressWarnings("unused")
    private void onCellClicked(ImageView cell, int row, int col, GridPane gameGrid) {
        if (state.gameOver || state.map[row][col] == 0) return;

        if (firstSelected != null && firstSelected == cell) {
            resetSelection();
            return;
        }

        if (firstSelected == null) {
            setFirstSelection(cell);
            return;
        }

        handleSecondSelection(cell, row, col, gameGrid);
    }

    private void resetSelection() {
        firstSelected.setOpacity(1.0);
        firstSelected = null;
    }

    private void setFirstSelection(ImageView cell) {
        firstSelected = cell;
        cell.setOpacity(0.5);
    }

    private void handleSecondSelection(ImageView cell, int row, int col, GridPane gameGrid) {
        int[] pos1 = findPosition(firstSelected);
        if (logic.canLink(pos1[0], pos1[1], row, col)) {
            removeMatchedCells(pos1, row, col, gameGrid);
            updateScore();
            checkWinCondition();
        } else {
            resetSelection();
        }
    }

    private void removeMatchedCells(int[] pos1, int row, int col, GridPane gameGrid) {
        state.map[pos1[0]][pos1[1]] = 0;
        state.map[row][col] = 0;
        gameGrid.getChildren().removeAll(firstSelected, cells[row][col]);
        resetSelection();
    }

    private void updateScore() {
        state.score += 10;
        scoreLabel.setText("得分: " + state.score);
    }

    private void checkWinCondition() {
        if (logic.checkWin()) {
            long elapsedTime = (System.currentTimeMillis() - state.startTime) / 1000;
            int remainingTime = GameState.TIMER_LIMIT - (int) elapsedTime;
            state.score += remainingTime * 2;
            scoreLabel.setText("得分: " + state.score);
            showAlert("恭喜", "你赢了！最终得分: " + state.score);
        }
    }

    private int[] findPosition(ImageView cell) {
        for (int row = 0; row < GameState.ROWS; row++) {
            for (int col = 0; col < GameState.COLS; col++) {
                if (cells[row][col] == cell) {
                    return new int[]{row, col};
                }
            }
        }
        return new int[]{-1, -1};
    }

    private void startTimer() {
        state.startTime = System.currentTimeMillis();
        timer = new AnimationTimer() {
            @Override
            public void handle(long now) {
                if (state.gameOver) {
                    this.stop();
                    return;
                }
                updateTimerDisplay();
            }
        };
        timer.start();
    }

    private void updateTimerDisplay() {
        long elapsedTime = (System.currentTimeMillis() - state.startTime) / 1000;
        int remaining = GameState.TIMER_LIMIT - (int) elapsedTime;

        if (remaining >= 0) {
            timeLabel.setText("剩余时间: " + remaining + " 秒");
            timeLabel.setTextFill(remaining <= 10 ? Color.RED : Color.BLACK);
        } else {
            timer.stop();
            state.gameOver = true;
            showAlert("时间到", "游戏结束！最终得分: " + state.score);
        }
    }

    private void resetGame(GridPane gameGrid) {
        stopTimer();
        clearGameGrid(gameGrid);
        resetGameState();
        logic.generateMap();
        initGameGrid(gameGrid);
        startTimer();
    }

    private void stopTimer() {
        if (timer != null) {
            timer.stop();
        }
    }

    private void clearGameGrid(GridPane gameGrid) {
        gameGrid.getChildren().clear();
        for (int i = 0; i < GameState.ROWS; i++) {
            for (int j = 0; j < GameState.COLS; j++) {
                cells[i][j] = null;
            }
        }
    }

    private void resetGameState() {
        state.gameOver = false;
        state.score = 0;
        state.hintsLeft = GameState.MAX_HINTS;
        state.shufflesLeft = GameState.MAX_SHUFFLES;
        firstSelected = null;
        hintActive = false;

        updateUIAfterReset();
    }

    private void updateUIAfterReset() {
        timeLabel.setTextFill(Color.BLACK);
        timeLabel.setText("剩余时间: " + GameState.TIMER_LIMIT + " 秒");
        scoreLabel.setText("得分: 0");
        hintLabel.setText("提示: " + state.hintsLeft + " 次");
        shuffleLabel.setText("重排: " + state.shufflesLeft + " 次");
        hintBtn.setText("提示 (" + state.hintsLeft + ")");
        shuffleBtn.setText("重排 (" + state.shufflesLeft + ")");
    }

    private void showHint(GridPane gameGrid) {
        if (hintActive || state.gameOver || state.hintsLeft <= 0) return;

        List<int[]> pairs = logic.findAllRemovablePairs();
        if (pairs.isEmpty()) {
            showAlert("提示", "没有可消除的图案对！");
            return;
        }

        useHint(pairs);
    }

    private void useHint(List<int[]> pairs) {
        state.hintsLeft--;
        updateHintUI();

        int[] pair = pairs.get(new Random().nextInt(pairs.size()));
        hintPos1 = new int[]{pair[0], pair[1]};
        hintPos2 = new int[]{pair[2], pair[3]};

        highlightHintPair();
        scheduleHintRemoval();
    }

    private void updateHintUI() {
        hintLabel.setText("提示: " + state.hintsLeft + " 次");
        hintBtn.setText("提示 (" + state.hintsLeft + ")");
    }

    private void highlightHintPair() {
        cells[hintPos1[0]][hintPos1[1]].setOpacity(0.5);
        cells[hintPos2[0]][hintPos2[1]].setOpacity(0.5);
        hintActive = true;
    }

    private void scheduleHintRemoval() {
        new Thread(() -> {
            try {
                Thread.sleep(GameState.HINT_DURATION);
                Platform.runLater(this::removeHintHighlight);
            } catch (InterruptedException e) {
                LOGGER.log(Level.WARNING, "提示高亮线程被中断", e);
                Thread.currentThread().interrupt();
            }
        }).start();
    }

    private void removeHintHighlight() {
        if (hintActive) {
            cells[hintPos1[0]][hintPos1[1]].setOpacity(1.0);
            cells[hintPos2[0]][hintPos2[1]].setOpacity(1.0);
            hintActive = false;
        }
    }

    private void shuffleMap(GridPane gameGrid) {
        if (state.gameOver || state.shufflesLeft <= 0) return;

        state.shufflesLeft--;
        updateShuffleUI();

        List<Integer> remaining = collectRemainingIcons();
        Collections.shuffle(remaining);
        redistributeIcons(remaining);

        resetSelectionState();
        redrawGameGrid(gameGrid);
    }

    private void updateShuffleUI() {
        shuffleLabel.setText("重排: " + state.shufflesLeft + " 次");
        shuffleBtn.setText("重排 (" + state.shufflesLeft + ")");
    }

    private List<Integer> collectRemainingIcons() {
        List<Integer> remaining = new ArrayList<>();
        for (int row = 0; row < GameState.ROWS; row++) {
            for (int col = 0; col < GameState.COLS; col++) {
                if (state.map[row][col] != 0) {
                    remaining.add(state.map[row][col]);
                }
            }
        }
        return remaining;
    }

    private void redistributeIcons(List<Integer> remaining) {
        int index = 0;
        for (int row = 0; row < GameState.ROWS; row++) {
            for (int col = 0; col < GameState.COLS; col++) {
                if (state.map[row][col] != 0) {
                    state.map[row][col] = remaining.get(index++);
                }
            }
        }
    }

    private void resetSelectionState() {
        if (firstSelected != null) {
            firstSelected.setOpacity(1.0);
            firstSelected = null;
        }
    }

    private void redrawGameGrid(GridPane gameGrid) {
        gameGrid.getChildren().clear();
        initGameGrid(gameGrid);
    }

    private void showAlert(String title, String content) {
        Platform.runLater(() -> {
            Alert alert = new Alert(Alert.AlertType.INFORMATION);
            alert.setTitle(title);
            alert.setHeaderText(null);
            alert.setContentText(content);
            alert.showAndWait();
        });
    }
}